package com.matrix.im.netty;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.matrix.im.domain.model.ChatMessage;
import com.matrix.im.domain.model.SystemMessage;
import com.matrix.im.interfaces.dto.SendMessageDTO;
import com.matrix.im.netty.session.SessionManager;
import com.matrix.im.protocol.MessageProto;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author 有点甜
 * @since 2025/8/6
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class MessagePusher {

    private final SessionManager sessionManager;
    private final ObjectMapper objectMapper;

    public void pushPrivateMessage(ChatMessage chatMessage) {
        Long toUserId = chatMessage.getToUserId();
        Channel channel = sessionManager.getChannel(toUserId);

        if (channel != null && channel.isActive()) {
            try {
                SendMessageDTO.MessageBodyDTO bodyDto = objectMapper.readValue(chatMessage.getContent(), SendMessageDTO.MessageBodyDTO.class);

                MessageProto.MessageBody.ContentType protoContentType = MessageProto.MessageBody.ContentType.valueOf(bodyDto.getType());

                MessageProto.MessageBody protoBody = MessageProto.MessageBody.newBuilder()
                        .setType(protoContentType)
                        .setContent(bodyDto.getContent())
                        .build();

                MessageProto.ServerPushMessage pushMessage = MessageProto.ServerPushMessage.newBuilder()
                        .setMessageId(chatMessage.getId())
                        .setFromUserId(chatMessage.getFromUserId())
                        .setTimestamp(chatMessage.getTimestamp().getTime())
                        .setBody(protoBody)
                        .build();

                MessageProto.MessagePackage messagePackage = MessageProto.MessagePackage.newBuilder()
                        .setPackageType(MessageProto.PackageType.SERVER_PUSH_MESSAGE)
                        .setServerPushMessage(pushMessage)
                        .build();

                channel.writeAndFlush(messagePackage);
                log.info("Successfully pushed private message {} to user {}", chatMessage.getId(), toUserId);
            } catch (Exception e) {
                log.error("Failed to process and push private message {}", chatMessage.getId(), e);
            }
        } else {
            log.warn("Cannot push message {}: User {} is offline or channel is inactive.", chatMessage.getId(), toUserId);
        }
    }

    public void pushSystemMessage(SystemMessage systemMessage) {
        Long toUserId = systemMessage.getUserId();
        Channel channel = sessionManager.getChannel(toUserId);

        if (channel != null && channel.isActive()) {

            MessageProto.MessageBody protoBody = MessageProto.MessageBody.newBuilder()
                    .setType(MessageProto.MessageBody.ContentType.SYSTEM_NOTICE)
                    .setContent(systemMessage.getContent())
                    .build();

            MessageProto.ServerPushMessage pushMessage = MessageProto.ServerPushMessage.newBuilder()
                    .setMessageId(systemMessage.getId())
                    .setFromUserId(0L)
                    .setTimestamp(systemMessage.getTimestamp().getTime())
                    .setBody(protoBody)
                    .build();

            MessageProto.MessagePackage messagePackage = MessageProto.MessagePackage.newBuilder()
                    .setPackageType(MessageProto.PackageType.SERVER_PUSH_MESSAGE)
                    .setServerPushMessage(pushMessage)
                    .build();

            channel.writeAndFlush(messagePackage);
            log.info("Successfully pushed system message {} to user {}", systemMessage.getId(), toUserId);
        } else {
            log.warn("Cannot push system message {}: User {} is offline or channel is inactive.", systemMessage.getId(), toUserId);
        }
    }
}